#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <math.h>
#include <sys/types.h>
#include <fftw3.h>

#include "analize.h"

typedef struct instance_instance {
  double* _fftw_in;
  double* _fftw_out;
  fftw_plan _fftw_plan;
  
  u_int16_t _num_samples;
  
  double _sample_freq;
  double _average;
  
  double _max;
  u_int16_t _index;
  
  float* _cosine;
  
  double _frequency;
  
} analize_instance;

#define instance ((analize_instance*)handle)

analize_handle analize_open(u_int16_t samples) {
  analize_handle handle = malloc(sizeof(analize_instance));
  u_int16_t i;
  
  fprintf(stdout, "initialize analize..\n");
  
  instance->_average = 0.0;
  
  instance->_max = 0.0;
  instance->_index = 0;
  instance->_num_samples = samples;
  
  instance->_fftw_in = malloc(sizeof(double) * instance->_num_samples);
  instance->_fftw_out = malloc(sizeof(double) * instance->_num_samples); //  / 2 + 1
  
  instance->_fftw_plan = fftw_plan_r2r_1d(instance->_num_samples, instance->_fftw_in, instance->_fftw_out, FFTW_R2HC, FFTW_ESTIMATE);
  
  for(i = 0; i < instance->_num_samples; i++) instance->_cosine[i] = 0.54 - (0.46 * cos(2.0 * M_PI * (float)i/instance->_num_samples));
  
  return handle;
}

void analize_setrate(analize_handle handle, u_int16_t rate) {
  instance->_sample_freq = ((double) rate) / instance->_num_samples;
}

void analize_close(analize_handle handle) {
  fprintf(stdout, "finalize analize..\n");
  
  fftw_destroy_plan(instance->_fftw_plan);
  
  //free(instance->_cosine);
  free(instance->_fftw_out);
  free(instance->_fftw_in);
  free(instance);
}

void analize_filldata(analize_handle handle, int16_t* data, u_int16_t skip, u_int16_t step) {
  u_int16_t i;
  
  instance->_average = 0.0;
  
  for (i=0; i<instance->_num_samples; i++){
    instance->_fftw_in[i] = ((double) *(data + i*step + skip)) / 32768.0;
    instance->_average += fabs(instance->_fftw_in[i]);
  }
  
  instance->_average /= instance->_num_samples;
  
}

void analize_execute(analize_handle handle) {
  u_int16_t i;
  double t;
  //printf("fourier transform\n");
  
  fftw_execute(instance->_fftw_plan);
  
  //printf("D:%f\n", instance->_fftw_out[0]);
  
  //printf("find band\n");
  
  instance->_max = 0.0;
  instance->_index = 0;
  
  for (i=2; i<instance->_num_samples/16; i++) {
    t = instance->_fftw_out[i] * instance->_fftw_out[i] + instance->_fftw_out[instance->_num_samples - i] * instance->_fftw_out[instance->_num_samples - i];
    if (t > instance->_max) {
      instance->_max = t;
      instance->_index = i;
    }
  }
  
  instance->_frequency = instance->_sample_freq * instance->_index;
  
  //printf("M:%f I:%d F:%f\n",  instance->_integral, instance->_index, instance->_frequency);
}

double analize_average(analize_handle handle) {
  return instance->_average;
}

double analize_frequency(analize_handle handle) {
  return instance->_frequency;
}


